package com.oss.service.oss;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oss.dto.oss.positionmanage.*;
import com.oss.dto.report.PositionSummaryPageDto;
import com.oss.entity.oss.PositionManage;
import com.oss.entity.oss.Student;
import com.oss.entity.oss.TradeManage;
import com.oss.enums.BuyOrSellEnum;
import com.oss.enums.IsDeletedEnum;
import com.oss.mapper.oss.PositionManageMapper;
import com.oss.service.system.DictionaryService;
import com.oss.util.SnowFlakeUtil;
import com.oss.vo.oss.position.PositionManageSummaryVO;
import com.oss.vo.oss.position.PositionManageVO;
import com.oss.vo.oss.report.PositionSummaryVO;
import com.oss.vo.oss.student.StudentVO;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PositionManageService extends ServiceImpl<PositionManageMapper, PositionManage> {
    @Autowired
    DictionaryService dictionaryService;
    @Autowired
    StudentService studentService;
    @Autowired
    HttpServletRequest request;
    @Autowired
    TradeManageService tradeManageService;
    @Autowired
    InstrumentService instrumentService;
    @Autowired
    LastPriceService lastPriceService;
    @Autowired
    CalendarService calendarService;

    public IPage<PositionManageVO> selectByPage(PageDto dto) {
        LambdaQueryWrapper<PositionManage> wrapper = new LambdaQueryWrapper<PositionManage>();
        wrapper.eq(PositionManage::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.eq(StringUtils.isNotBlank(dto.getInstrumentCode()),PositionManage::getInstrumentCode, dto.getInstrumentCode());
        wrapper.eq(StringUtils.isNotBlank(dto.getVarietyCode()),PositionManage::getVarietyCode, dto.getVarietyCode());
        wrapper.eq(StringUtils.isNotBlank(dto.getOptionType()),PositionManage::getOptionType, dto.getOptionType());
        wrapper.eq(dto.getPositionDate() != null,PositionManage::getPositionDate, dto.getPositionDate());
        wrapper.eq(StringUtils.isNotBlank(dto.getStudentID()),PositionManage::getStudentID, dto.getStudentID());
        wrapper.orderByDesc(PositionManage::getCreateTime);
        String originHeader = request.getHeader("oss-origin");
        String roleHeader = request.getHeader("oss-role");
        // 校验用户角色 , 如果角色是admin,则查询所有数据
        if (StringUtils.isNotBlank(roleHeader) && roleHeader.contains("admin")) {

        } else {
            // 后台管理端和网页, 只要不是admin角色, 登录时, 只能查询自己账号新增的数据
            // dataSource=1表示系统新增
            wrapper.eq(PositionManage::getDataSource,1);
            String studentID = request.getHeader("oss-studentID");
            wrapper.eq(PositionManage::getStudentID,studentID);
        }
        IPage<PositionManage> page = this.page(new Page<>(dto.getPageNo(), dto.getPageSize()), wrapper);
        Map<String,String> dictionaryMap = new HashMap<>();
        Map<String, StudentVO> studentMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(page.getRecords())){
            // 获取期权类型字典值
            dictionaryMap = dictionaryService.getDictionaryMapByTypeCode("OptionType");
            Set<String> ids = page.getRecords().stream().map(PositionManage::getStudentID).collect(Collectors.toSet());
            studentMap = studentService.selectByIDs(ids);
        }
        Map<String, String> finalDictionaryMap = dictionaryMap;
        Map<String, StudentVO> finalStudentMap = studentMap;
        return page.convert(entity->{
            PositionManageVO vo = new PositionManageVO();
            BeanUtils.copyProperties(entity, vo);
            vo.setOptionType(finalDictionaryMap.get(entity.getOptionType()));
            if (finalStudentMap.containsKey(entity.getStudentID())){
                StudentVO studentVO = finalStudentMap.get(entity.getStudentID());
                vo.setStudentID(studentVO.getId());
                vo.setStudentPhone(studentVO.getPhone());
                vo.setStudentName(studentVO.getName());
                vo.setStudentWechatID(studentVO.getWechatID());
                vo.setStudentAccount(studentVO.getAccount());
            }
            return vo;
        });
    }

    public String add(AddDto dto) {
        PositionManage entity = new PositionManage();
        BeanUtils.copyProperties(dto,entity);
        entity.setId(SnowFlakeUtil.getID());
        entity.setDataSource(1);
        this.save(entity);
        return "操作成功";
    }

    public String updateData(UpdateDto dto) {
        PositionManage entity = new PositionManage();
        BeanUtils.copyProperties(dto,entity);
        this.updateById(entity);
        return "操作成功";
    }

    public String delete(DeleteDto dto) {
        LambdaUpdateWrapper<PositionManage> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(PositionManage::getId,dto.getId());
        lambdaUpdateWrapper.set(PositionManage::getIsDeleted,IsDeletedEnum.YES.getFlag());
        this.update(null,lambdaUpdateWrapper);
        return "操作成功";
    }

    public List<PositionManage> getByInstrumentCode(String instrumentCode) {
        LambdaQueryWrapper<PositionManage> wrapper = new LambdaQueryWrapper<PositionManage>();
        wrapper.eq(PositionManage::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.eq(PositionManage::getInstrumentCode,instrumentCode);
        return this.list(wrapper);
    }

    /**
     * 删除数据(根据学员ID, 持仓日期 , 数据来源=外部推送)
     * @param studentID
     * @param positionDate
     */
    public void deleteByAccountAndDate(String studentID, LocalDate positionDate){
        LambdaUpdateWrapper<PositionManage> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(PositionManage::getStudentID,studentID);
        lambdaUpdateWrapper.eq(PositionManage::getPositionDate,positionDate);
        lambdaUpdateWrapper.eq(PositionManage::getIsDeleted,IsDeletedEnum.NO.getFlag());
        lambdaUpdateWrapper.set(PositionManage::getIsDeleted,IsDeletedEnum.YES.getFlag());
        this.update(null,lambdaUpdateWrapper);
    }
    public String importData(ImportDto dto) {
        List<PositionManage> addList = new ArrayList<>();
        Set<String> accountSet = dto.getList().stream().map(ImportDetailDto::getAccount).collect(Collectors.toSet());
        Map<String, String> studentAccountMap = studentService.getByAccountSet(accountSet);
        for (ImportDetailDto item : dto.getList()) {
            if (studentAccountMap.containsKey(item.getAccount())){
                String studentID = studentAccountMap.get(item.getAccount());
                deleteByAccountAndDate(studentID,item.getPositionDate());
                PositionManage entity = new PositionManage();
                BeanUtils.copyProperties(item,entity);
                entity.setStudentID(studentID);
                entity.setId(SnowFlakeUtil.getID());
                entity.setCreatorId("-1");
                addList.add(entity);
            } else {
                log.warn(item.getAccount()+"此账号对应的学员不存在; "+ "需要插入的数据="+ JSON.toJSONString(item));
            }
        }
        if (CollectionUtils.isNotEmpty(addList)){
            this.saveBatch(addList);
        }
        return "操作成功";
    }

    /**
     * 持仓汇总
     * @param dto
     * @return
     */
    public List<PositionManageVO> positionSummary(CountDto dto) {
        List<PositionManageVO> returnList = new ArrayList<>();
        List<PositionManageVO> list = countByList(dto);
        // 按照合约分组
        Map<String,List<PositionManageVO>> map = list.stream().collect(Collectors.groupingBy(PositionManageVO::getInstrumentCode));
        for (Map.Entry<String, List<PositionManageVO>> entry : map.entrySet()) {
            PositionManageVO vo = new PositionManageVO();
            String instrumentCode = entry.getKey();
            List<PositionManageVO> positionManageVOS = entry.getValue();
            vo.setId(SnowFlakeUtil.getID());
            vo.setInstrumentCode(instrumentCode);
            vo.setBuyPosition(positionManageVOS.stream().map(item->item.getBuyPosition() == null ? BigDecimal.ZERO:item.getBuyPosition()).reduce(BigDecimal.ZERO,BigDecimal::add));
            // 买总价
            BigDecimal buyPriceTotal = positionManageVOS.stream().map(item->{
                BigDecimal buyPosition = getBigDecimalVal(item.getBuyPosition());
                BigDecimal buyAveragePrice = getBigDecimalVal(item.getBuyAveragePrice());
                return buyPosition.multiply(buyAveragePrice);
            }).reduce(BigDecimal.ZERO,BigDecimal::add);
            BigDecimal buyAveragePrice = vo.getBuyPosition().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : buyPriceTotal.divide(vo.getBuyPosition(), BigDecimal.ROUND_HALF_UP);
            vo.setBuyAveragePrice(buyAveragePrice);
            vo.setSellPosition(positionManageVOS.stream().map(item->item.getSellPosition() == null ? BigDecimal.ZERO:item.getSellPosition()).reduce(BigDecimal.ZERO,BigDecimal::add));
            // 卖总价
            BigDecimal sellPriceTotal = positionManageVOS.stream().map(item->{
                BigDecimal sellPosition = getBigDecimalVal(item.getSellPosition());
                BigDecimal sellAveragePrice = getBigDecimalVal(item.getSellAveragePrice());
                return sellPosition.multiply(sellAveragePrice);
            }).reduce(BigDecimal.ZERO,BigDecimal::add);
            BigDecimal sellAveragePrice = vo.getSellPosition().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : sellPriceTotal.divide(vo.getSellPosition(), BigDecimal.ROUND_HALF_UP);
            vo.setSellAveragePrice(sellAveragePrice);
            vo.setAvailableAmount(positionManageVOS.stream().map(PositionManageVO::getAvailableAmount).reduce(BigDecimal.ZERO,BigDecimal::add));
            vo.setFloatingProfitLoss(positionManageVOS.stream().map(PositionManageVO::getFloatingProfitLoss).reduce(BigDecimal.ZERO,BigDecimal::add));
            vo.setTradeMargin(positionManageVOS.stream().map(PositionManageVO::getTradeMargin).reduce(BigDecimal.ZERO,BigDecimal::add));
            vo.setChildren(positionManageVOS);
            returnList.add(vo);
        }
        return returnList;
    }

    public List<PositionManageVO> countByList(CountDto dto) {
        String headerStudentID = request.getHeader("oss-studentID");
        // 网页端查看
        if (StringUtils.isNotEmpty(headerStudentID) && CollectionUtils.isEmpty(dto.getStudentIDs())) {
            dto.setStudentIDs(Arrays.asList(headerStudentID));
            dto.setDataSource(1);
        } else {
            // 后台管理端, 查询全部学员
            if (CollectionUtils.isEmpty(dto.getStudentIDs())){
                // 获取全部学员
                List<Student> studentList = studentService.getAll();
                dto.setStudentIDs(studentList.stream().map(Student::getId).collect(Collectors.toList()));
            }
        }
        List<PositionManageVO> returnList = new ArrayList<>();
        boolean flag = calendarService.isTradeingDay(dto.getPositionDate());
        // 选择的日期非交易日, 往后延长到下一个交易日
        if (flag == false) {
            LocalDate date = calendarService.getNextTradingDay(dto.getPositionDate());
            dto.setPositionDate(date);
            returnList = selectTodayTrade(dto);
        } else {
            // 选择的持仓日期是当日/未来
            if (dto.getPositionDate().equals(LocalDate.now()) || dto.getPositionDate().isAfter(LocalDate.now())) {
                returnList = selectTodayTrade(dto);
            } else {
                // 查询历史持仓
                returnList = selectHistoryPosition(dto);
            }
        }
        Map<String, StudentVO> studentMap = new HashMap<>();
        Set<String> ids = returnList.stream().map(PositionManageVO::getStudentID).collect(Collectors.toSet());
        studentMap = studentService.selectByIDs(ids);
        Map<String, StudentVO> finalStudentMap = studentMap;
        returnList.stream().forEach(vo->{
            if (finalStudentMap.containsKey(vo.getStudentID())){
                StudentVO studentVO = finalStudentMap.get(vo.getStudentID());
                vo.setStudentID(studentVO.getId());
                vo.setStudentPhone(studentVO.getPhone());
                vo.setStudentName(studentVO.getName());
                vo.setStudentWechatID(studentVO.getWechatID());
                vo.setStudentAccount(studentVO.getAccount());
            }
        });
        return returnList;
    }

    /**
     * 查询历史持仓 , 就查询对应账号的对应日期持仓
     * @param dto
     * @return
     */
    public List<PositionManageVO> selectHistoryPosition(CountDto dto){
        List<PositionManageVO> returnList = new ArrayList<>();
        LambdaQueryWrapper<PositionManage> wrapper = new LambdaQueryWrapper<PositionManage>();
        wrapper.eq(PositionManage::getIsDeleted, IsDeletedEnum.NO.getFlag());
        wrapper.eq(StringUtils.isNotBlank(dto.getInstrumentCode()),PositionManage::getInstrumentCode, dto.getInstrumentCode());
        wrapper.eq(dto.getPositionDate() != null,PositionManage::getPositionDate, dto.getPositionDate());
        wrapper.in(CollectionUtils.isNotEmpty(dto.getStudentIDs()),PositionManage::getStudentID, dto.getStudentIDs());
        List<PositionManage> list = this.list(wrapper);
        Set<String> instrumentCodeSet = list.stream().map(PositionManage::getInstrumentCode).collect(Collectors.toSet());
        // 交易单位
        Map<String,Integer> volumeMultipleMap = new HashMap<>();
        // 最新价
        Map<String,BigDecimal> lastPriceleMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){
            volumeMultipleMap = instrumentService.selectVolumeMultipleByInstrumentCodeSet(instrumentCodeSet);
            lastPriceleMap = lastPriceService.selectHistoryLastPriceByInstrumentCodeSet(instrumentCodeSet,dto.getPositionDate());
        }
        if (CollectionUtils.isNotEmpty(list)){
            // 按照学员ID分组
            Map<String,List<PositionManage>> groupByStudentIdList = list.stream().collect(Collectors.groupingBy(PositionManage::getStudentID));
            for (Map.Entry<String, List<PositionManage>> groupByStudentIdEntry : groupByStudentIdList.entrySet()) {
                String studentID = groupByStudentIdEntry.getKey();
                List<PositionManage> sameStudentIdList = groupByStudentIdEntry.getValue();
                // 按照持仓日期分组
                Map<LocalDate,List<PositionManage>> groupByPositionDateList = sameStudentIdList.stream().collect(Collectors.groupingBy(PositionManage::getPositionDate));
                for (Map.Entry<LocalDate,List<PositionManage>> groupByPositionDateEntry : groupByPositionDateList.entrySet()) {
                    LocalDate positionDate = groupByPositionDateEntry.getKey();
                    List<PositionManage> samePositionDateList = groupByPositionDateEntry.getValue();
                    // 按照合约分组
                    Map<String,List<PositionManage>> groupByInstrumentCodeList = samePositionDateList.stream().collect(Collectors.groupingBy(PositionManage::getInstrumentCode));
                    for (Map.Entry<String,List<PositionManage>> groupByInstrumentCodeEntry : groupByInstrumentCodeList.entrySet()) {
                        String instrumentCode = groupByInstrumentCodeEntry.getKey();
                        List<PositionManage> sameInstrumentCodeList = groupByInstrumentCodeEntry.getValue();
                        if (CollectionUtils.isNotEmpty(sameInstrumentCodeList)){
                            // 交易单位
                            BigDecimal volumeMultiple = volumeMultipleMap.containsKey(instrumentCode) ? new BigDecimal(volumeMultipleMap.get(instrumentCode)):BigDecimal.ZERO;
                            // 最新价
                            BigDecimal lastPricele = lastPriceleMap.containsKey(instrumentCode) ? lastPriceleMap.get(instrumentCode) :BigDecimal.ZERO;
                            PositionManageVO vo = new PositionManageVO();
                            vo.setStudentID(studentID);
                            vo.setPositionDate(positionDate);
                            vo.setInstrumentCode(instrumentCode);
                            // 买持仓
                            BigDecimal buyPosition = sameInstrumentCodeList.stream().map(item->item.getBuyPosition() == null ? BigDecimal.ZERO:item.getBuyPosition()).reduce(BigDecimal.ZERO, BigDecimal::add);
                            // 买均价
                            BigDecimal buyAveragePrice = sameInstrumentCodeList.stream().map(item->item.getBuyAveragePrice() == null ? BigDecimal.ZERO:item.getBuyAveragePrice()).reduce(BigDecimal.ZERO, BigDecimal::add)
                                    .divide(BigDecimal.valueOf(sameInstrumentCodeList.size()), BigDecimal.ROUND_HALF_UP);
                            BigDecimal sellPosition = sameInstrumentCodeList.stream().map(item->item.getSellPosition() == null ? BigDecimal.ZERO:item.getSellPosition()).reduce(BigDecimal.ZERO, BigDecimal::add);
                            BigDecimal sellAveragePrice = sameInstrumentCodeList.stream().map(item->item.getSellAveragePrice() == null ? BigDecimal.ZERO:item.getSellAveragePrice()).reduce(BigDecimal.ZERO, BigDecimal::add)
                                    .divide(BigDecimal.valueOf(sameInstrumentCodeList.size()), BigDecimal.ROUND_HALF_UP);
                            vo.setBuyPosition(buyPosition);
                            vo.setSellPosition(sellPosition);
                            vo.setBuyAveragePrice(buyAveragePrice);
                            vo.setSellAveragePrice(sellAveragePrice);

                            vo.setLastPrice(lastPricele);
                            vo.setVolumeMultiple(volumeMultiple);
                            // 手数 = 买持仓 + 卖持仓
                            BigDecimal volumn = buyPosition.add(sellPosition);
                            vo.setAvailableAmount(volumn.multiply(lastPricele).multiply(volumeMultiple));
                            // 买开持仓市值 = 当前价*买持仓*交易单位
                            BigDecimal buyAvailableAmount = lastPricele.multiply(vo.getBuyPosition()).multiply(volumeMultiple);
                            // 卖开持仓市值 = 当前价*卖持仓*交易单位
                            BigDecimal sellAvailableAmount =lastPricele.multiply(vo.getSellPosition().multiply(volumeMultiple));
                            // 浮动盈亏=买开的持仓市值-买开均价*买开手数*合约管理中的每手乘数(此列改为交易单位)+卖开均价*卖开手数*合约管理中的每手乘数(此列改为交易单位)+卖开的持仓市值
                            BigDecimal floatingProfitLoss = buyAvailableAmount
                                    .subtract(vo.getBuyAveragePrice().multiply(vo.getBuyPosition()).multiply(volumeMultiple))
                                    .add(vo.getSellAveragePrice().multiply(vo.getSellPosition()).multiply(volumeMultiple))
                                    .subtract(sellAvailableAmount);
                            vo.setFloatingProfitLoss(floatingProfitLoss);
                            BigDecimal tradeMargin = sameInstrumentCodeList.stream().map(item->item.getTradeMargin() == null ? BigDecimal.ZERO:item.getTradeMargin()).reduce(BigDecimal.ZERO, BigDecimal::add);
                            vo.setTradeMargin(tradeMargin);
                            returnList.add(0,vo);
                        }
                    }
                }
            }
        }
        // 按照持仓日期倒序
        returnList.sort((o1,o2)->o2.getPositionDate().compareTo(o1.getPositionDate()));
        return returnList;
    }

    /**
     * 查询当日持仓
     * @param dto
     * @return
     */
    public List<PositionManageVO> selectTodayTrade(CountDto dto){
        List<PositionManageVO> returnList = new ArrayList<>();
        // 交易日
        LocalDate tradeDate = dto.getPositionDate();
        // 1. 所有账号的当前天的交易数据
        List<TradeManage> tradeList = tradeManageService.selectCurrnetDayDataBySIdAndVarietyCode(dto);
        // 历史交易取前一个交易日的历史数据(没有为空)
        dto.setPositionDate(calendarService.getLastTradingDay(dto.getPositionDate()));
        // 2. 所有账号的历史持仓
        List<PositionManageVO> historyPositionList = selectHistoryPosition(dto);
        // 查询当日交易时 , 所有的持仓日期都显示为当日
        historyPositionList.forEach(item->{
            item.setPositionDate(tradeDate);
        });
        // 3. 根据合约代码 , 查询交易单位和最新价
        Set<String> instrumentCodeSet = tradeList.stream().map(TradeManage::getInstrumentCode).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(historyPositionList)){
            returnList.addAll(historyPositionList);
        }
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){

            instrumentCodeSet.addAll(historyPositionList.stream().map(PositionManageVO::getInstrumentCode).collect(Collectors.toSet()));
        }
        Map<String,Integer> volumeMultipleMap = new HashMap<>();
        Map<String,BigDecimal> lastPriceleMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){
            volumeMultipleMap = instrumentService.selectVolumeMultipleByInstrumentCodeSet(instrumentCodeSet);
            lastPriceleMap = lastPriceService.selectLastPriceByInstrumentCodeSet(instrumentCodeSet);
        }
        // 4. 按学员ID分组(当日交易)
        Map<String,List<TradeManage>> sidMap = tradeList.stream().collect(Collectors.groupingBy(TradeManage::getStudentID));
        for (Map.Entry<String, List<TradeManage>> entry : sidMap.entrySet()) {
            String studentID = entry.getKey();
            List<TradeManage> sidList = entry.getValue();
            // 获取相同学员历史持仓
            List<PositionManageVO> sameSidHistoryPositionList = historyPositionList.stream().filter(item->item.getStudentID().equals(studentID) ).collect(Collectors.toList());
            // 5. 按合约代码分组(当日交易)
            Map<String,List<TradeManage>> instrumentCodeMap = sidList.stream().collect(Collectors.groupingBy(TradeManage::getInstrumentCode));
            // 6. 循环当日交易, 合并到相同学员的历史持仓中去(如果历史持仓的合约代码已存在 , 计算买卖持仓, 不存在直接添加)
            for (Map.Entry<String, List<TradeManage>> entry2 : instrumentCodeMap.entrySet()) {
                // 7. 计算买持仓, 买均价 , 卖持仓, 卖均价
                String instrumentCode = entry2.getKey();
                List<TradeManage> sameCodeTradeList = entry2.getValue();
                // 合约对应的交易单位
                BigDecimal volumeMultiple = volumeMultipleMap.containsKey(instrumentCode) ? new BigDecimal(volumeMultipleMap.get(instrumentCode)):BigDecimal.ZERO;
                // 合约对应的最新价
                BigDecimal lastPricele = lastPriceleMap.containsKey(instrumentCode) ? lastPriceleMap.get(instrumentCode) :BigDecimal.ZERO;
                // 相同合约的历史持仓
                List<PositionManageVO> sameInstrumentCodeHistoryPositionList = sameSidHistoryPositionList.stream().filter(item->item.getInstrumentCode().equals(instrumentCode)).collect(Collectors.toList());
                // 计算今日交易的 买持仓 , 买均价 , 卖持仓 , 卖均价-----------------------------------------------------------------------------开始
                // 今日买开数量 = sum(买开)- sum(卖平)
                BigDecimal buyCall = sameCodeTradeList.stream().filter(item->item.getOffsetFlag().equals(BuyOrSellEnum.BuyCall.getValue())).map(item->item.getTradeVolume()==null?BigDecimal.ZERO:item.getTradeVolume()).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 今日卖平 = sum(卖平)
                BigDecimal sellPut = sameCodeTradeList.stream().filter(item->item.getOffsetFlag().equals(BuyOrSellEnum.SellPut.getValue())).map(item->item.getTradeVolume()==null?BigDecimal.ZERO:item.getTradeVolume()).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 买持仓 = 买开 - 卖平
                BigDecimal buyPosition = buyCall.subtract(sellPut);
                // 今日买开总额 = sum(买开*成交单价) - sum(卖平*成交单价)
                BigDecimal buyCallTotal =  sameCodeTradeList.stream().filter(item->
                        item.getOffsetFlag().equals(BuyOrSellEnum.BuyCall.getValue()) || item.getOffsetFlag().equals(BuyOrSellEnum.SellPut.getValue())).map(item->{
                    BigDecimal tradeVolume = item.getTradeVolume();
                    tradeVolume = tradeVolume == null ? BigDecimal.ZERO : tradeVolume;
                    BigDecimal tradeSinglePrice = item.getTradeSinglePrice();
                    tradeSinglePrice = tradeSinglePrice == null ? BigDecimal.ZERO : tradeSinglePrice;
                    if (item.getOffsetFlag().equals(BuyOrSellEnum.BuyCall.getValue())) {
                        return  tradeVolume.multiply(tradeSinglePrice);
                    } else {
                        // 卖平取反
                        return  tradeVolume.multiply(tradeSinglePrice).negate();
                    }
                }).reduce(BigDecimal.ZERO, BigDecimal::add);

                // 买均价 = SUM(买开*成交价)(就是今日买开总额) / 买持仓
                BigDecimal buyAveragePrice = bigDecimalIsZero(buyPosition) ? BigDecimal.ZERO : buyCallTotal.divide(buyPosition, BigDecimal.ROUND_HALF_UP);

                // 今日卖开数量 = sum(卖开)
                BigDecimal sellCall = sameCodeTradeList.stream().filter(item->item.getOffsetFlag().equals(BuyOrSellEnum.SellCall.getValue())).map(item->item.getTradeVolume()==null?BigDecimal.ZERO:item.getTradeVolume()).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 今日买平数量 = sum(买平)
                BigDecimal buyPut = sameCodeTradeList.stream().filter(item->item.getOffsetFlag().equals(BuyOrSellEnum.BuyPut.getValue())).map(item->item.getTradeVolume()==null?BigDecimal.ZERO:item.getTradeVolume()).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 卖持仓=卖开-买平
                BigDecimal sellPosition = sellCall.subtract(buyPut);
                // 今日卖开总额 = sum(卖开*成交单价)-sum(买平*成交单价)
                BigDecimal sellCallTotal =  sameCodeTradeList.stream().filter(item->
                        item.getOffsetFlag().equals(BuyOrSellEnum.SellCall.getValue()) || item.getOffsetFlag().equals(BuyOrSellEnum.BuyPut.getValue())).map(item->{
                    BigDecimal tradeVolume = item.getTradeVolume();
                    tradeVolume = tradeVolume == null ? BigDecimal.ZERO : tradeVolume;
                    BigDecimal tradeSinglePrice = item.getTradeSinglePrice();
                    tradeSinglePrice = tradeSinglePrice == null ? BigDecimal.ZERO : tradeSinglePrice;
                    if (item.getOffsetFlag().equals(BuyOrSellEnum.SellCall.getValue())) {
                        return tradeVolume.multiply(tradeSinglePrice);
                    } else {
                        // 买平取反
                        return tradeVolume.multiply(tradeSinglePrice).negate();
                    }
                }).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 卖均价 = sum(卖开*成交价)(就是今日卖开总额)/SUM（卖持仓）
                BigDecimal sellAveragePrice = bigDecimalIsZero(sellPosition) ? BigDecimal.ZERO : sellCallTotal.divide(sellPosition, BigDecimal.ROUND_HALF_UP);
                // 计算今日交易的 买持仓 , 买均价 , 卖持仓 , 卖均价-----------------------------------------------------------------------------结束

                // 8. 历史持仓 中存在和 今日交易 相同合约代码的交易(进一步查看买卖方向是否相同 , 不同 , 直接添加一条新记录 , 相同则计算买卖持仓,均价等)
                if (CollectionUtils.isNotEmpty(sameInstrumentCodeHistoryPositionList)) {
                    // 历史持仓中一般只有一条
                    PositionManageVO historyPosition = sameInstrumentCodeHistoryPositionList.get(0);
                    // 历史买持仓
                    BigDecimal historyBuyPosition = historyPosition.getBuyPosition() == null ? BigDecimal.ZERO : historyPosition.getBuyPosition();
                    // 历史买均价
                    BigDecimal historyBuyAveragePrice = historyPosition.getBuyAveragePrice() == null ? BigDecimal.ZERO : historyPosition.getBuyAveragePrice();
                    // 历史卖持仓
                    BigDecimal historySellPosition = historyPosition.getSellPosition() == null ? BigDecimal.ZERO : historyPosition.getSellPosition();
                    // 历史卖均价
                    BigDecimal historySellAveragePrice = historyPosition.getSellAveragePrice() == null ? BigDecimal.ZERO : historyPosition.getSellAveragePrice();
                    // 历史保证金
                    BigDecimal historyTradeMargin = historyPosition.getTradeMargin() == null ? BigDecimal.ZERO : historyPosition.getTradeMargin();
                    // 历史买开总额 = 历史买持仓 * 历史买均价
                    BigDecimal historyBuyCallTotal = historyBuyPosition.multiply(historyBuyAveragePrice);
                    // 历史卖开总额
                    BigDecimal historySellCallTotal = historySellPosition.multiply(historySellAveragePrice);
                    // 买持仓 = 上个交易日的历史买持仓(相同合约) + (买开 - 卖平)(这个就是今日买持仓)
                    BigDecimal buyPositionTotal = historyBuyPosition.add(buyCall.subtract(sellPut));
                    // 卖持仓 = 上个交易日的历史卖持仓(相同合约) + (卖开-买平)(这个就是今日卖持仓)
                    BigDecimal sellPositionTotal = historySellPosition.add(sellCall.subtract(buyPut));

                    // 买均价 = (上个交易日的历史持仓(相同合约)*买均价(就是历史买开总额) + SUM(买开*成交价)(就是今日买开总额) / 买持仓
                    buyAveragePrice = bigDecimalIsZero(buyPosition) ? BigDecimal.ZERO : historyBuyCallTotal.add(buyCallTotal).divide(buyPositionTotal, BigDecimal.ROUND_HALF_UP);
                    // 卖均价 = sum(卖开*成交价)(就是今日卖开总额) + SUM(卖开 * 成交价)(就是今日卖开总额) / SUM（卖持仓）
                    sellAveragePrice = bigDecimalIsZero(sellPosition) ? BigDecimal.ZERO : historySellCallTotal.add(sellCallTotal).divide(sellPositionTotal, BigDecimal.ROUND_HALF_UP);
                    // 今日买开不等于0
                    if (buyPosition.compareTo(BigDecimal.ZERO) != 0) {
                        // 历史买持仓不等于0(今日交易和历史交易同事存在合约相同 , 且买卖方向相同 , 重新计算)
                        if (historyBuyPosition.compareTo(BigDecimal.ZERO) != 0) {
                            reBuildHistoryBuyPostion(historyPosition,buyPositionTotal,buyAveragePrice,lastPricele,volumeMultiple,buyCall);
                        } else {
                            // 历史买持仓等于0(今日交易和历史交易同事存在合约相同 , 且买卖方向不相同 , 直接添加一条新的)
                            PositionManageVO vo = buildTradeBuyPostion(buyPosition,buyAveragePrice,lastPricele,volumeMultiple,buyCall);
                            vo.setStudentID(studentID);
                            vo.setPositionDate(tradeDate);
                            vo.setInstrumentCode(instrumentCode);
                            returnList.add(vo);
                        }

                    }
                    // 今日卖开不等于0
                    if (sellPosition.compareTo(BigDecimal.ZERO) != 0) {
                        // 历史卖持仓不等于0(今日交易和历史交易同事存在合约相同 , 且买卖方向相同 , 重新计算)
                        if (historySellPosition.compareTo(BigDecimal.ZERO) != 0) {
                            // 交易保证金计算的合约单价
                            BigDecimal tradeMarginLastPrice = instrumentService.getTradeMarginLastPriceByInstrumentCode(instrumentCode);
                            BigDecimal tradeMarginRate = instrumentService.getRateByInstrumentCode(instrumentCode);
                            // 保证金 = 保证金最新价(取父级合约的) * 交易单位 * 保证金比率 * 手数(不是卖持仓)
                            BigDecimal tradeMargin = tradeMarginLastPrice.multiply(volumeMultiple).multiply(tradeMarginRate).multiply(sellCall);
                            // 新的保证金 = 历史保证金+当前交易的保证金
                            BigDecimal totalTradeMargin = historyTradeMargin.add(tradeMargin);
                            historyPosition.setTradeMarginRate(tradeMarginRate);
                            historyPosition.setTradeMarginLastPrice(tradeMarginLastPrice);
                            reBuildHistorySellPostion(historyPosition,sellPositionTotal,sellAveragePrice,lastPricele,volumeMultiple,sellCall,totalTradeMargin);
                        } else {
                            // 历史卖持仓等于0(今日交易和历史交易同事存在合约相同 , 且买卖方向不相同 , 直接添加一条新的)
                            // 交易保证金计算的合约单价
                            BigDecimal tradeMarginLastPrice = instrumentService.getTradeMarginLastPriceByInstrumentCode(instrumentCode);
                            BigDecimal tradeMarginRate = instrumentService.getRateByInstrumentCode(instrumentCode);
                            // 保证金 = 保证金最新价(取父级合约的) * 交易单位 * 保证金比率 * 手数(不是卖持仓)
                            BigDecimal tradeMargin = tradeMarginLastPrice.multiply(volumeMultiple).multiply(tradeMarginRate).multiply(sellCall);
                            PositionManageVO vo = buildTradeSellPostion(sellPosition,sellAveragePrice,lastPricele,volumeMultiple,sellCall,tradeMargin);
                            vo.setStudentID(studentID);
                            vo.setPositionDate(tradeDate);
                            vo.setInstrumentCode(instrumentCode);
                            vo.setTradeMarginRate(tradeMarginRate);
                            vo.setTradeMarginLastPrice(tradeMarginLastPrice);
                            returnList.add(vo);
                        }
                    }

                } else {
                    // 9. 历史持仓 中和 今日交易 不存在相同合约代码的交易 , 直接添加记录

                    // 买持仓不等于0 , 则添加买方向的交易持仓
                    if (buyPosition.compareTo(BigDecimal.ZERO) != 0) {
                        PositionManageVO vo = buildTradeBuyPostion(buyPosition,buyAveragePrice,lastPricele,volumeMultiple,buyCall);
                        vo.setStudentID(studentID);
                        vo.setPositionDate(tradeDate);
                        vo.setInstrumentCode(instrumentCode);
                        returnList.add(vo);
                    }
                    // 卖持仓不等于0 , 则添加卖方向的交易持仓
                    if (sellPosition.compareTo(BigDecimal.ZERO) != 0) {
                        // 交易保证金计算的合约单价
                        BigDecimal tradeMarginLastPrice = instrumentService.getTradeMarginLastPriceByInstrumentCode(instrumentCode);
                        BigDecimal tradeMarginRate = instrumentService.getRateByInstrumentCode(instrumentCode);
                        // 保证金 = 保证金最新价(取父级合约的) * 交易单位 * 保证金比率 * 手数(不是卖持仓)
                        BigDecimal tradeMargin = tradeMarginLastPrice.multiply(volumeMultiple).multiply(tradeMarginRate).multiply(sellCall);
                        PositionManageVO vo = buildTradeSellPostion(sellPosition,sellAveragePrice,lastPricele,volumeMultiple,sellCall,tradeMargin);
                        vo.setStudentID(studentID);
                        vo.setPositionDate(tradeDate);
                        vo.setInstrumentCode(instrumentCode);
                        vo.setTradeMarginRate(tradeMarginRate);
                        vo.setTradeMarginLastPrice(tradeMarginLastPrice);
                        returnList.add(vo);
                    }
                }

            }
        }
        returnList.sort((o1, o2) -> o2.getInstrumentCode().compareTo(o1.getInstrumentCode()));
        return returnList;
    }

    /**
     * 添加交易对应的持仓(买方向)
     * @param buyPosition
     * @param buyAveragePrice
     * @param lastPricele
     * @param volumeMultiple
     * @param buyCall
     * @return
     */
    public PositionManageVO buildTradeBuyPostion(BigDecimal buyPosition,BigDecimal buyAveragePrice,BigDecimal lastPricele,BigDecimal volumeMultiple,BigDecimal buyCall ){
        // 计算单边买方向时 , 卖方向相关金额为零
        PositionManageVO vo = new PositionManageVO();
        vo.setBuyPosition(buyPosition);
        vo.setBuyAveragePrice(buyAveragePrice);
        vo.setSellPosition(BigDecimal.ZERO);
        vo.setSellAveragePrice(BigDecimal.ZERO);
        vo.setLastPrice(lastPricele);
        vo.setVolumeMultiple(volumeMultiple);
        // 买开持仓市值 = 当前价*买持仓*交易单位
        BigDecimal buyCallAvailableAmount = lastPricele.multiply(buyPosition).multiply(volumeMultiple);
        // 卖开持仓市值 = 当前价*卖持仓(负数)*交易单位
        BigDecimal sellCallAvailableAmount = BigDecimal.ZERO;
        // 持仓市值 = 买开持仓市值+卖开持仓市值
        BigDecimal availableAmount = buyCallAvailableAmount.add(sellCallAvailableAmount);
        // 回填持仓市值
        vo.setAvailableAmount(availableAmount);

        // 买开成本 = 买均价*买开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal butCallCost = buyAveragePrice.multiply(buyCall).multiply(volumeMultiple);
        // 卖开成本 = 卖均价*卖开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal cellCallCost = BigDecimal.ZERO;

        // 浮动盈亏 = (最新价-买均价) * 买持仓 * 交易单位
        BigDecimal floatingProfitLoss = lastPricele.subtract(buyAveragePrice).multiply(buyPosition).multiply(volumeMultiple);
        vo.setFloatingProfitLoss(floatingProfitLoss);
        // 交易保证金累加
        BigDecimal tradeMargin = BigDecimal.ZERO;
        vo.setTradeMargin(tradeMargin);
        return vo;
    }

    /**
     * 添加交易对应的持仓(卖方向)
     * @param sellPosition
     * @param sellAveragePrice
     * @param lastPricele
     * @param volumeMultiple
     * @param sellCall
     * @param tradeMargin
     * @return
     */
    public PositionManageVO buildTradeSellPostion(BigDecimal sellPosition,BigDecimal sellAveragePrice,BigDecimal lastPricele,BigDecimal volumeMultiple,BigDecimal sellCall,BigDecimal tradeMargin){
        // 计算单边卖方向时 , 买方向相关金额为零
        PositionManageVO vo = new PositionManageVO();

        vo.setBuyPosition(BigDecimal.ZERO);
        vo.setBuyAveragePrice(BigDecimal.ZERO);
        vo.setSellPosition(sellPosition);
        vo.setSellAveragePrice(sellAveragePrice);

        vo.setLastPrice(lastPricele);
        vo.setVolumeMultiple(volumeMultiple);
        // 买开持仓市值 = 当前价*买持仓*交易单位
        BigDecimal buyCallAvailableAmount = BigDecimal.ZERO;
        // 卖开持仓市值 = 当前价*卖持仓(负数)*交易单位
        BigDecimal sellCallAvailableAmount = lastPricele.multiply(sellPosition).multiply(volumeMultiple).negate();
        // 持仓市值 = 买开持仓市值+卖开持仓市值
        BigDecimal availableAmount = buyCallAvailableAmount.add(sellCallAvailableAmount);
        // 回填持仓市值
        vo.setAvailableAmount(availableAmount);

        // 买开成本 = 买均价*买开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal butCallCost = BigDecimal.ZERO;
        // 卖开成本 = 卖均价*卖开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal cellCallCost = sellAveragePrice.multiply(sellCall).multiply(volumeMultiple);

        // 浮动盈亏 = (卖均价-最新价) * 卖持仓 * 交易单位
        BigDecimal floatingProfitLoss = sellAveragePrice.subtract(lastPricele).multiply(sellPosition).multiply(volumeMultiple);
        vo.setFloatingProfitLoss(floatingProfitLoss);
        // 交易保证金累加
        vo.setTradeMargin(tradeMargin);

        return vo;
    }

    /**
     * 重新计算历史持仓 (买方向)
     * @param historyPositionVO
     * @param buyPosition
     * @param buyAveragePrice
     * @param lastPricele
     * @param volumeMultiple
     * @param buyCall
     */
    public void reBuildHistoryBuyPostion(PositionManageVO historyPositionVO,BigDecimal buyPosition,BigDecimal buyAveragePrice,BigDecimal lastPricele,BigDecimal volumeMultiple,BigDecimal buyCall ){
        // 计算单边买方向时 , 卖方向相关金额为零
        historyPositionVO.setBuyPosition(buyPosition);
        historyPositionVO.setBuyAveragePrice(buyAveragePrice);
        historyPositionVO.setSellPosition(BigDecimal.ZERO);
        historyPositionVO.setSellAveragePrice(BigDecimal.ZERO);
        historyPositionVO.setLastPrice(lastPricele);
        historyPositionVO.setVolumeMultiple(volumeMultiple);
        // 买开持仓市值 = 当前价*买持仓*交易单位
        BigDecimal buyCallAvailableAmount = lastPricele.multiply(buyPosition).multiply(volumeMultiple);
        // 卖开持仓市值 = 当前价*卖持仓(负数)*交易单位
        BigDecimal sellCallAvailableAmount = BigDecimal.ZERO;
        // 持仓市值 = 买开持仓市值+卖开持仓市值
        BigDecimal availableAmount = buyCallAvailableAmount.add(sellCallAvailableAmount);
        // 回填持仓市值
        historyPositionVO.setAvailableAmount(availableAmount);

        // 买开成本 = 买均价*买开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal butCallCost = buyAveragePrice.multiply(buyCall).multiply(volumeMultiple);
        // 卖开成本 = 卖均价*卖开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal cellCallCost = BigDecimal.ZERO;

        // 浮动盈亏 = (最新价-买均价) * 买持仓 * 交易单位
        BigDecimal floatingProfitLoss = lastPricele.subtract(buyAveragePrice).multiply(buyPosition).multiply(volumeMultiple);
        historyPositionVO.setFloatingProfitLoss(floatingProfitLoss);
        // 交易保证金累加
        BigDecimal tradeMargin = BigDecimal.ZERO;
        historyPositionVO.setTradeMargin(tradeMargin);
    }

    /**
     * 重新计算历史持仓的相关数据
     * @param historyPositionVO
     * @param sellPosition
     * @param sellAveragePrice
     * @param lastPricele
     * @param volumeMultiple
     * @param sellCall
     * @param tradeMargin
     */
    public void reBuildHistorySellPostion(PositionManageVO historyPositionVO,BigDecimal sellPosition,BigDecimal sellAveragePrice,BigDecimal lastPricele,BigDecimal volumeMultiple,BigDecimal sellCall,BigDecimal tradeMargin){
        // 计算单边卖方向时 , 买方向相关金额为零

        historyPositionVO.setBuyPosition(BigDecimal.ZERO);
        historyPositionVO.setBuyAveragePrice(BigDecimal.ZERO);
        historyPositionVO.setSellPosition(sellPosition);
        historyPositionVO.setSellAveragePrice(sellAveragePrice);

        historyPositionVO.setLastPrice(lastPricele);
        historyPositionVO.setVolumeMultiple(volumeMultiple);
        // 买开持仓市值 = 当前价*买持仓*交易单位
        BigDecimal buyCallAvailableAmount = BigDecimal.ZERO;
        // 卖开持仓市值 = 当前价*卖持仓(负数)*交易单位
        BigDecimal sellCallAvailableAmount = lastPricele.multiply(sellPosition).multiply(volumeMultiple).negate();
        // 持仓市值 = 买开持仓市值+卖开持仓市值
        BigDecimal availableAmount = buyCallAvailableAmount.add(sellCallAvailableAmount);
        // 回填持仓市值
        historyPositionVO.setAvailableAmount(availableAmount);

        // 买开成本 = 买均价*买开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal butCallCost = BigDecimal.ZERO;
        // 卖开成本 = 卖均价*卖开手数*合约管理中的每手乘数(此列改为交易单位)
        BigDecimal cellCallCost = sellAveragePrice.multiply(sellCall).multiply(volumeMultiple);

        // 浮动盈亏 = (买均价-最新价) * 卖持仓 * 交易单位
        BigDecimal floatingProfitLoss = sellAveragePrice.subtract(lastPricele).multiply(sellPosition).multiply(volumeMultiple);
        historyPositionVO.setFloatingProfitLoss(floatingProfitLoss);
        // 交易保证金
        historyPositionVO.setTradeMargin(tradeMargin);
    }

    /**
     * BigDecimal数值是否等于0 , 返回true=0
     * @param val
     * @return
     */
    public boolean bigDecimalIsZero(BigDecimal val){
        return val==null ? true : val.compareTo(BigDecimal.ZERO) == 0;
    }
    // 获取BigDecimal值非空
    public BigDecimal getBigDecimalVal(BigDecimal val){
        return val==null ? BigDecimal.ZERO : val;
    }
}